/*******************************************************************
 *
 * Copyright (C), 2021-2022, LS, All rights reserved.
 *
 * Author      : 
 * Create Time : 2021-09-22
 * Version     : v0.1
 * Description : 
 *******************************************************************/
 
/*----------------------------Head file----------------------------*/
#include "hal_battery.h"
#include "user_config.h"
#include "bsp_hw_config.h"

#define HAL_BAT_LOG_EN      1

#if HAL_BAT_LOG_EN
#include "log.h"
#define HAL_BAT_LOG         LOG
#else
#define HAL_BAT_LOG(...)
#endif

/*----------------------------macro file---------------------------*/
#define ADC_DIFF_MODE_CFG           0
#define ADC_HIGH_RESOLUTION_CFG     ADC_BIT(BSP_BATT_ADC_CH_NUM)

/*----------------------------type define--------------------------*/

/*----------------------------var define---------------------------*/
#if(BATT_CHARGE_ENABLE)
static hal_charge_evt_cb_t hal_charge_evt_cb = NULL;
#endif
static hal_batt_adc_evt_cb_t hal_batt_adc_evt_cb = NULL;

//bypass mode, 0~0.8V, use external divider resistor.
//attenuation mode, 0~3.2V, use MCU internal divider resistor.
static const adc_Cfg_t cfg = {
    .channel = ADC_BIT(BSP_BATT_ADC_CH_NUM),
    .is_continue_mode = FALSE,
    .is_differential_mode = ADC_DIFF_MODE_CFG,
    .is_high_resolution = ADC_HIGH_RESOLUTION_CFG,       //0: attenuation mode, 1: bypass mode
};

/*-------------------------func declaration------------------------*/

/*-----------------------------------------------------------------*/

bool hal_batt_full_charge_state_get(void)
{
#if(BATT_CHARGE_ENABLE)

#if(BAT_FULL_CHG_DET_ENABLE)
    if(true == hal_gpio_read(BSP_DET_CHG_PIN_NUM) && true == hal_gpio_read(BSP_FULL_CHG_PIN_NUM))
        return true;
    else
        return false;
#else
    return false;
#endif  //#if(BAT_FULL_CHG_DET_ENABLE)

#else
    return false;
#endif  //#if(BATT_CHARGE_ENABLE)
}


bool hal_batt_charging_state_get(void)
{
#if(BATT_CHARGE_ENABLE)
    if(true == hal_gpio_read(BSP_DET_CHG_PIN_NUM))
        return true;
    else
        return false;
#else
    return false;
#endif
}

#if(BATT_CHARGE_ENABLE)
static void batt_charge_evt_hdl(GPIO_Pin_e pin, IO_Wakeup_Pol_e type)
{
    //HAL_BAT_LOG("batt_charge_evt_hdl: %d\n", type);
    if(type == POSEDGE) {
        if(hal_charge_evt_cb) {
            hal_charge_evt_cb(true);
        }
    }
    else {
        if(hal_charge_evt_cb) {
            hal_charge_evt_cb(false);
        }
    }
}
#endif


int hal_batt_charge_hw_init(hal_charge_evt_cb_t cb)
{
#if(BATT_CHARGE_ENABLE)
    int ret = PPlus_SUCCESS;

    ret += hal_gpio_pin_init(BSP_DET_CHG_PIN_NUM, GPIO_INPUT);
    hal_gpio_pull_set(BSP_DET_CHG_PIN_NUM, PULL_DOWN);     //PHY6222 must pull down, or it can not wake mcu by charging in.
    ret += hal_gpioin_register(BSP_DET_CHG_PIN_NUM, batt_charge_evt_hdl, NULL);

#if(BAT_FULL_CHG_DET_ENABLE)
    ret += hal_gpio_pin_init(BSP_FULL_CHG_PIN_NUM, GPIO_INPUT);
    hal_gpio_pull_set(BSP_FULL_CHG_PIN_NUM, FLOATING);
#endif

    hal_charge_evt_cb = cb;

    return ret;
#else
    return 0;
#endif
}


static void hal_batt_adc_evt(adc_Evt_t* pev)
{
    if(pev->type != HAL_ADC_EVT_DATA)
        return;

    if(BIT(BSP_BATT_ADC_CH_NUM) == cfg.channel) {
        //Use load calibration adc value
        //float f_adc_value = hal_adc_value_cal(BSP_BATT_ADC_CH_NUM, pev->data, pev->size, ADC_HIGH_RESOLUTION_CFG, ADC_DIFF_MODE_CFG);       //1nF
        float f_adc_value = hal_adc_value_cal(BSP_BATT_ADC_CH_NUM, pev->data, pev->size, TRUE, ADC_DIFF_MODE_CFG);  //Use bypass mode, and diff mode disabled. (100nF)
        uint32_t adc_value = (uint32_t)(f_adc_value*1000);
        if(hal_batt_adc_evt_cb) {
            hal_batt_adc_evt_cb(adc_value);
        }
    }
}


int hal_batt_adc_measure(void)
{
    int ret = HAL_BAT_SUCCESS;

    if(hal_adc_work_state_get()) {
        hal_adc_stop();     //It do not trigger adc interrupt sometime, so we need to stop adc first, or it will cause error return or system crash.
        HAL_BAT_LOG("adc_stop\n");
        ret = HAL_BAT_STOP_ABNORMAL;
    }
    if(PPlus_SUCCESS != hal_adc_config_channel(cfg, hal_batt_adc_evt)) {
        HAL_BAT_LOG("batt adc config err: %d.\n", ret);
        return HAL_BAT_CONF_FAIL;
    }
    hal_adc_start();
    
    return ret;
}


int hal_batt_adc_init(hal_batt_adc_evt_cb_t cb)
{
    hal_batt_adc_evt_cb = cb;
    hal_gpio_pull_set(BSP_BATT_ADC_PIN_NUM, FLOATING);
    
    return 0;
}


void hal_batt_adc_deinit(void)
{
    hal_adc_stop();
}


void hal_batt_charge_hw_deinit(void)
{

}


void hal_system_adc_init(void)
{
    hal_adc_init();
    //Charge cap
    hal_gpio_pull_set(BSP_BATT_ADC_PIN_NUM, GPIO_FLOATING);
    hal_gpio_ds_control(BSP_BATT_ADC_PIN_NUM, Bit_ENABLE);
    hal_gpio_cfg_analog_io(BSP_BATT_ADC_PIN_NUM, Bit_ENABLE);
    app_delay_ms(800);      //Need some delay for detecting stable adc later.
    hal_gpio_cfg_analog_io(BSP_BATT_ADC_PIN_NUM, Bit_DISABLE);
    hal_gpio_pin_init(BSP_BATT_ADC_PIN_NUM, GPIO_INPUT);
}

